import pandas as pd
from conf import conf
from core.constant import *
from datetime import datetime as datetime_


class ConsoleModel:
    def __init__(self, super_model):
        self.super_model = super_model
        self.draw_data_len = None

        self.k_cont_width = conf.KChart.k_cont_width.value
        self.index = conf.KChart.index.value
        self.k_max_num = 0

        # 显示至console面板的相关变量
        self.index_value = str(self.index)
        self.all_index_value = None
        self.time_values = None  # 本次展示的所有signal及相应时间
        self.signal_value = ''  # 当前信号的序号值，默认显示最新的
        self.all_signal_value = None  # 总信号值的数量
        self.message_file_value = None  # 本次signal对应文件名
        self.message_show_content = ''  # 本次展示的信号对应内容
        self.message_df: pd.DataFrame = None  # 消息文件对应的df数据
        self.move_unit: int = 1  # 左右移动跨度

        # 实际全量绘制的数据
        self.draw_data_k_section = None
        self.draw_data_vol_section = None
        self.draw_data_factor_1_section = None
        self.draw_data_factor_2_section = None

        # 运行过程的功能性变量
        self.is_show_crosshair = False
        self.time_span = 0
        self.change_range = 0.0
        pass

    def sec_init(self):
        self.draw_data_len = len(self.super_model.draw_data_k)
        self.all_index_value = str(-self.draw_data_len)
        self.time_values = self.get_signal_ls()  # 本次展示的所有signal及相应时间
        # self.signal_value = ''  # 当前信号的序号值，默认不显示
        self.all_signal_value = str(len(self.time_values))  # 总信号值的数量

    def get_signal_ls(self):
        data_cols = self.super_model.draw_data_k.columns.tolist()
        exist_sig_ls = []
        for sig in SigType:
            if sig.value in data_cols:
                exist_sig_ls.append(sig.value)
        if exist_sig_ls:
            not_nan_bool = None
            for sig in exist_sig_ls:
                if not_nan_bool is None:
                    not_nan_bool = ~self.super_model.draw_data_k[sig].isna()
                else:
                    not_nan_bool = not_nan_bool | ~self.super_model.draw_data_k[sig].isna()
            not_nan_rows = self.super_model.draw_data_k[not_nan_bool]
            return not_nan_rows.index.tolist()
        else:
            return []

    def gen_k_max_num(self):
        # 填充console_view组件的缺省值
        # 计算当前最大容纳K线的数量
        self.k_max_num = self.super_model.k_lines_model.ele_size[0] // self.k_cont_width - 1  # 最后一个K线不显示，美观

    def gen_draw_data_section(self):
        # 根据index和k_max_num截取出需要子窗口展示的数据
        if self.k_max_num >= self.draw_data_len:
            self.draw_data_k_section = self.super_model.draw_data_k
            self.draw_data_vol_section = self.super_model.draw_data_vol
            self.draw_data_factor_1_section = self.super_model.draw_data_factor_1
            self.draw_data_factor_2_section = self.super_model.draw_data_factor_2
        elif self.index == -1:
            self.draw_data_k_section = self.super_model.draw_data_k.iloc[self.index - self.k_max_num + 1:]
            self.draw_data_vol_section = self.super_model.draw_data_vol.iloc[self.index - self.k_max_num + 1:]
            self.draw_data_factor_1_section = self.super_model.draw_data_factor_1.iloc[self.index - self.k_max_num + 1:]
            self.draw_data_factor_2_section = self.super_model.draw_data_factor_2.iloc[self.index - self.k_max_num + 1:]
        elif -1 >= self.index >= -self.draw_data_len + self.k_max_num + 1:
            self.draw_data_k_section = self.super_model.draw_data_k.iloc[
                                       self.index - self.k_max_num + 1: self.index + 1]
            self.draw_data_vol_section = self.super_model.draw_data_vol.iloc[
                                         self.index - self.k_max_num + 1: self.index + 1]
            self.draw_data_factor_1_section = self.super_model.draw_data_factor_1.iloc[
                                              self.index - self.k_max_num + 1: self.index + 1]
            self.draw_data_factor_2_section = self.super_model.draw_data_factor_2.iloc[
                                              self.index - self.k_max_num + 1: self.index + 1]
        else:
            raise ValueError("index值或传入数据异常。")

    def change_window_size(self):
        # 获取当前各view的size（预留，用于增加K线图窗口大小变化对各子窗口大小的更改）
        pass

    def change_index_k_cont_width(self, index=None, k_cont_width=None):
        if index is None or k_cont_width is None:
            pass
        elif self.draw_data_len < self.k_max_num:
            print("K线数量少于当前可呈现的最大数量，不支持调整index。")
        elif index > -1 or index < -self.draw_data_len + self.k_max_num + 1:
            print(f"index超出范围限制。{index}")
            return
        elif k_cont_width < conf.KChart.k_cont_width_range.value[0] or k_cont_width > \
                conf.KChart.k_cont_width_range.value[1]:
            print("k_cont_width超出范围限制。")
            return
        else:
            self.index = index
            self.k_cont_width = k_cont_width
        self.gen_k_max_num()
        self.gen_draw_data_section()

    def show_message(self):
        if self.message_df is None:
            content = "未设置消息文件。"
            self.super_model.super_view.console_view.console_layout.entry_message_show_var.set(content)
        else:
            time_str = self.super_model.super_view.console_view.console_layout.combobox_time_var.get()
            time_datetime = datetime_.strptime(time_str, "%Y-%m-%d %H:%M:%S")
            if time_datetime in self.message_df.index:
                content = self.message_df.loc[time_datetime, "内容"]
                self.super_model.super_view.console_view.console_layout.entry_message_show_var.set(content)
            else:
                content = "当前不存在对应消息。"
                self.super_model.super_view.console_view.console_layout.entry_message_show_var.set(content)

    def get_index_from_time(self, time_val):
        return self.super_model.draw_data_k.index.get_loc(time_val) - len(self.super_model.draw_data_k)

    def on_index_skip(self):
        index = int(self.super_model.super_view.console_view.console_layout.entry_index_var.get())
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()

        pass

    def on_time_skip(self):
        combobox_time_str = self.super_model.super_view.console_view.console_layout.combobox_time_var.get()
        combobox_time = pd.to_datetime(combobox_time_str)
        index = self.get_index_from_time(combobox_time)
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_combobox_time_change(self):
        combobox_time_str = self.super_model.super_view.console_view.console_layout.combobox_time_var.get()
        combobox_time = pd.to_datetime(combobox_time_str)
        index = self.get_index_from_time(combobox_time)
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_signal_skip(self):
        self.signal_value = self.super_model.super_view.console_view.console_layout.entry_signal_var.get()
        signal = int(self.signal_value)
        # signal判断
        if signal > len(self.time_values) or signal < 1:
            print("signal序号异常")
            return
        # signal-1是self.time_value的正确索引
        time_val = self.time_values[signal - 1]
        index = self.get_index_from_time(time_val)
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_last_signal(self):
        if self.super_model.super_view.console_view.console_layout.entry_signal_var.get().isdigit():
            signal = int(self.super_model.super_view.console_view.console_layout.entry_signal_var.get())
        else:
            self.signal_value = '1'
            signal = int(self.signal_value)

        # signal-1是self.time_value的正确索引
        signal -= 1
        # signal判断
        if signal > len(self.time_values) or signal < 1:
            print("signal序号异常")
            return
        self.signal_value = str(signal)
        time_val = self.time_values[signal - 1]
        index = self.get_index_from_time(time_val)
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_next_signal(self):
        if self.super_model.super_view.console_view.console_layout.entry_signal_var.get().isdigit():
            signal = int(self.super_model.super_view.console_view.console_layout.entry_signal_var.get())
        else:
            self.signal_value = '1'
            signal = int(self.signal_value)

        # signal-1是self.time_value的正确索引
        signal += 1
        # signal判断
        if signal > len(self.time_values) or signal < 1:
            print("signal序号异常")
            return
        self.signal_value = str(signal)

        time_val = self.time_values[signal - 1]
        index = self.get_index_from_time(time_val)
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_up(self):
        index = self.index
        k_cont_width = self.k_cont_width + 1
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_down(self):
        index = self.index
        k_cont_width = self.k_cont_width - 1
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_left(self):
        index = self.index - self.move_unit
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_right(self):
        index = self.index + self.move_unit
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_left_5(self):
        index = self.index - 5
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_right_5(self):
        index = self.index + 5
        k_cont_width = self.k_cont_width
        self.change_index_k_cont_width(index, k_cont_width)
        self.super_model.refresh()
        pass

    def on_refresh(self):
        # 根据现有配置重新绘制一下
        # 执行刷新操作
        self.super_model.refresh()

        pass

    def on_reset(self):
        # 执行刷新操作
        self.super_model.reset()

        pass

    def on_crosshair_ok(self, event=None):
        is_show_str = self.super_model.super_view.console_view.console_layout.combobox_crosshair_var.get()
        if is_show_str == "显示":
            # 保留十字线配置并显示
            self.is_show_crosshair = True
            pass
        elif is_show_str == "不显示":
            # 保留十字线配置并隐藏
            self.is_show_crosshair = False
            # 额外清除残留的十字线
            self.super_model.refresh()
            pass
        else:
            raise ValueError(f"不支持的值{is_show_str}")

        pass

    def on_time_span_ok(self, event=None):
        time_span_str = self.super_model.super_view.console_view.console_layout.entry_time_span_var.get()
        # 将改动写入十字线配置并刷新显示
        self.time_span = int(time_span_str)
        pass

    def on_change_range_ok(self, event=None):
        change_range_str = self.super_model.super_view.console_view.console_layout.entry_change_range_var.get()
        # 将改动写入十字线配置并刷新显示
        self.change_range = float(change_range_str)
        pass

    def on_message_file_skip(self, event=None):
        # 读取消息文件内容
        path = self.super_model.super_view.console_view.console_layout.entry_message_var.get()
        # 将时间作为索引
        data = pd.read_csv(path, index_col=0)
        data.index = pd.to_datetime(data.index)
        self.message_df = data
        print("message.csv文件读取成功。")
        # 刷新显示下消息内容
        self.show_message()
        pass

    def on_resize(self, event=None):
        if event.widget == self.super_model.super_view.root:
            if event.width != self.super_model.prev_super_view_size[0] or event.height != self.super_model.prev_super_view_size[1]:
                # print(f"尺寸改变{[event.width, event.height]}")
                # 由于结构较乱，未实现窗口大小改变，令绘图面积随之改变的功能
                # 更新记录的窗口尺寸
                self.super_model.prev_super_view_size = [event.width, event.height]
                self.super_model.super_view_size = [event.width, event.height]
                self.super_model.sec_init()
                # 更改console_model的实际全量绘制的数据
                self.gen_k_max_num()
                self.gen_draw_data_section()
                # 改变窗口尺寸
                self.super_model.super_view.ele_view_instantiate()
                self.super_model.refresh()

    def on_move_unit_ok(self, event=None):
        change_range_str = self.super_model.super_view.console_view.console_layout.entry_move_unit_var.get()
        # 将改动写入十字线配置并刷新显示
        self.move_unit = int(change_range_str)

    pass
